/**
 * Some useful tips:
 * Override option by creating new option
 * 1. {...{'a': 1}, 'a': 2}
 * 2. Object.assign({}, {'a': 1 }, {'a': 2 })
 */

import type {
    ColDef,
    ValueFormatterParams,
    ITooltipComp,
    ITooltipParams,
    IDateFilterParams,
    NewValueParams,
    GridOptions,
} from "@ag-grid-community/core";

import {
    SelectionEditor
} from './components/edit';

import {
    sameDay,
    formatDateZhCn
} from '@/lib/utils';

import { getFileIcon } from '@/lib/file-icon';

import { filesize } from "filesize";

function dateFormatter(params: ValueFormatterParams) {
    if (params.value) {
        return formatDateZhCn(params.value);
    } else {
        return "";
    }
};

const DateFilterParams: IDateFilterParams = {
    comparator: (filterLocalDateAtMidnight: Date, cellValue: string) => {
        var dateAsString = cellValue;
        if (dateAsString == null) return -1;
        var cellDate = new Date(dateAsString);

        if (sameDay(cellDate, filterLocalDateAtMidnight)) return 0
        else if (cellDate < filterLocalDateAtMidnight) return -1;
        else if (cellDate > filterLocalDateAtMidnight) return 1;
        return 0;
    },
};


export const formatHeaderComponentTemplate = (iconLiteral: string) =>
    `<div class="ag-cell-label-container" role="presentation">
      <span data-ref="eMenu" class="ag-header-icon ag-header-cell-menu-button"></span>
      <span data-ref="eFilterButton" class="ag-header-icon ag-header-cell-filter-button"></span>
      <div data-ref="eLabel" class="ag-header-cell-label" role="presentation">
        <span data-ref="eSortOrder" class="ag-header-icon ag-sort-order"></span>
        <span data-ref="eSortAsc" class="ag-header-icon ag-sort-ascending-icon"></span>
        <span data-ref="eSortDesc" class="ag-header-icon ag-sort-descending-icon"></span>
        <span data-ref="eSortNone" class="ag-header-icon ag-sort-none-icon"></span>
        <span data-ref="eText" class="ag-header-cell-text" role="columnheader"></span>
        <sup class='tw:flex'>
          ${iconLiteral}
        </sup>
        <span data-ref="eFilter" class="ag-header-icon ag-filter-icon"></span>
      </div>
     </div>`;

export const questionMarkSvg = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="tw:size-4">
  <path fill-rule="evenodd" d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12Zm11.378-3.917c-.89-.777-2.366-.777-3.255 0a.75.75 0 0 1-.988-1.129c1.454-1.272 3.776-1.272 5.23 0 1.513 1.324 1.513 3.518 0 4.842a3.75 3.75 0 0 1-.837.552c-.676.328-1.028.774-1.028 1.152v.75a.75.75 0 0 1-1.5 0v-.75c0-1.279 1.06-2.107 1.875-2.502.182-.088.351-.199.503-.331.83-.727.83-1.857 0-2.584ZM12 18a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Z" clip-rule="evenodd" />
</svg>
`;

export const editableSvg = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="tw:size-4">
    <path d="M21.731 2.269a2.625 2.625 0 0 0-3.712 0l-1.157 1.157 3.712 3.712 1.157-1.157a2.625 2.625 0 0 0 0-3.712ZM19.513 8.199l-3.712-3.712-8.4 8.4a5.25 5.25 0 0 0-1.32 2.214l-.8 2.685a.75.75 0 0 0 .933.933l2.685-.8a5.25 5.25 0 0 0 2.214-1.32l8.4-8.4Z" />
    <path d="M5.25 5.25a3 3 0 0 0-3 3v10.5a3 3 0 0 0 3 3h10.5a3 3 0 0 0 3-3V13.5a.75.75 0 0 0-1.5 0v5.25a1.5 1.5 0 0 1-1.5 1.5H5.25a1.5 1.5 0 0 1-1.5-1.5V8.25a1.5 1.5 0 0 1 1.5-1.5h5.25a.75.75 0 0 0 0-1.5H5.25Z" />
</svg>
`;

export const questionMarkHeaderComponentParams = {
    template:
    formatHeaderComponentTemplate(questionMarkSvg)
};

export const editableHeaderComponentParams = {
    template:
    formatHeaderComponentTemplate(editableSvg)
}

export class HTMLTooltip implements ITooltipComp {
    eGui: any;
    init(params: ITooltipParams) {
        const eGui = (this.eGui = document.createElement('div'));
        eGui.classList.add('tw:shadow', 'tw:bg-base-100', 'tw:p-2', 'tw:rounded');
        eGui.innerHTML = params.value;
    }

    getGui() {
        return this.eGui;
    }
}

export function getEditableColTooltip() {
    return gettext('当前列可被编辑。鼠标双击 或者 鼠标右键选择编辑。');
}

export function getAuditStatusColorClass(s: string) {
    if (s == "approved") {
        return 'tw:bg-green-300';
    } else if (s == "pending") {
        return 'tw:bg-gray-300';
    } else if (s == "rejected") {
        return 'tw:bg-red-300'
    }
    return '';
}

function auditStatusCircleRender(params: ValueFormatterParams): string {
    const s = params.value;
    const colorClass = getAuditStatusColorClass(s);
    return `<span class="tw:size-5 tw:badge tw:badge-xs ${colorClass}"></span>`;
}

export const rowIDCol: ColDef = {
    headerName: gettext("行"),
    valueGetter: "node.rowIndex + 1",
    filter: false,
    width: 60,
    pinned: 'left',
};

export const IDCol: ColDef = {
    field: "id",
    headerName: gettext("ID"),
    width: 80,
    pinned: 'left',
}

// used in sort
const AuditStatusNumberMap = new Map([
    ['approved', 0],
    ['rejected', 1],
    ['pending', 2],
])

// It's better to create a readonly map
export const AuditStatusMap = new Map([
    ['approved', gettext('审核通过')],
    ['pending', gettext('审核中')],
    ['rejected', gettext('审核不通过')],
])

export const AuditStatusReverseMap = new Map([
    ['审核通过', 'approved'],
    ['审核中', 'pending'],
    ['审核不通过', 'rejected']
])

export const auditStatusCircleHeaderTooltip = `
<ul>
<li>
<span class="tw:size-5 tw:badge tw:badge-xs ${getAuditStatusColorClass('approved')}"></span>: ${gettext('审核通过')}
</li>

<li class='tw:flex tw:items-center'>
  <span class="tw:size-5 tw:badge tw:badge-xs ${getAuditStatusColorClass('pending')}"></span>: ${gettext('审核中')}
</li>

<li class='tw:flex tw:items-center'>
  <span class="tw:size-5 tw:badge tw:badge-xs ${getAuditStatusColorClass('rejected')}"></span>: ${gettext('审核不通过')}
</li>
</ul>
`;


export function auditStatusCol({
    field = 'audit_status',
    editable =  false,
}: {
    field?: string,
    editable?: boolean
}): ColDef {
    return {
        field: field,
        headerName: gettext("审核状态"),
        cellRenderer: auditStatusCircleRender,
        headerComponentParams: editable? {
            template: formatHeaderComponentTemplate(
                questionMarkSvg + editableSvg
            )
        } : questionMarkHeaderComponentParams,
        tooltipComponent: HTMLTooltip,
        headerTooltip: auditStatusCircleHeaderTooltip,
        width: 160,
        pinned: 'right',

        ...(editable && {
            editable: true,
            cellClass: 'tw:bg-base-200',
        }),
        cellEditor: SelectionEditor,
        cellEditorParams: {
            labelValueMap: AuditStatusReverseMap,
        },

        initialSort: 'desc',
        comparator: (va, vb, _na, _nb, _isDescending) => {
            // NOTE according to doc, the front itself will also invert the order if desc
            // so _isDescending is unnecessary here.
            const a_mapped = AuditStatusNumberMap.get(va);
            const b_mapped = AuditStatusNumberMap.get(vb);
            let res = a_mapped! - b_mapped!;
            return res;
        },

        filterParams: {
            textFormatter: (v: string) => {
                if (AuditStatusMap.has(v)) {
                    return AuditStatusMap.get(v);
                } else {
                    return v;
                }
            }
        }
    }
}

/**
 * Tips: use `cellRendererParams` to specify contentType and iconClass
 */
function fileNameCellRenener(params: ValueFormatterParams): string {
    const filename = params.value;
    const fileicon = getFileIcon({
        filename: filename,
        contentType: params.contentType,
        iconClass: params.iconClass
    });
    const res = `<div class='tw:flex tw:items-center tw:gap-2'>${fileicon} ${filename}</div>`;
    return res;
}

function fileSizeFormatter(params: ValueFormatterParams) {
    if (params.value) {
        return filesize(params.value);
    } else {
        return "";
    }
};


export function tf(field: string, headerName: string) {
    return {
        field: field,
        tooltipField: field,
        headerName: gettext(headerName)
    };
}

export const defaultColumnTypes: GridOptions['columnTypes'] = {
    date: {
        width: 200,
        valueFormatter: dateFormatter,
        filter: "agDateColumnFilter",
        filterParams: DateFilterParams,
    },
    file_size: {
        width: 120,
        filter: null, // TODO
        valueFormatter: fileSizeFormatter,
    },
    file_name: {
        cellRenderer: fileNameCellRenener,
        cellRendererParams: {
            iconClass: 'tw:size-4'
        },
        width: 200,
    },
    editable: {
        // onCellValueChanged: onCellValueChanged,
        editable: true,
        cellClass: 'tw:bg-base-200',
        headerComponentParams: editableHeaderComponentParams,
        headerTooltip: getEditableColTooltip(),
        valueSetter: (params) => {
            let newValue = params.newValue;
            // some django field is not nullable, so we use default value here
            if (newValue == null) {
                const dataType = params.colDef['cellDataType'];
                switch (dataType) {
                    case 'text':
                        newValue = "";
                        break;
                    case 'number':
                        newValue = 0;
                        break;
                }
            }
            const curFieldName = params.colDef['field']!;
            params.data[curFieldName] = newValue;
            return true;
        }, 
    }
}
